Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Mapbox, Inc.
// Licensed under the MIT License.

import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
import type {
ReadResourceResult,
ServerNotification,
ServerRequest
} from '@modelcontextprotocol/sdk/types.js';
import type { HttpRequest } from '../../utils/types.js';
import { BaseResource } from '../BaseResource.js';

/**
* Resource providing the latest official Mapbox documentation
* fetched from docs.mapbox.com/llms.txt
*/
export class MapboxDocumentationResource extends BaseResource {
readonly name = 'Mapbox Documentation';
readonly uri = 'resource://mapbox-documentation';
readonly description =
'Latest official Mapbox documentation, APIs, SDKs, and developer resources. Always up-to-date comprehensive coverage of all current Mapbox services.';
readonly mimeType = 'text/markdown';

private httpRequest: HttpRequest;

constructor(params: { httpRequest: HttpRequest }) {
super();
this.httpRequest = params.httpRequest;
}

public async readCallback(
uri: URL,
_extra: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<ReadResourceResult> {
try {
const response = await this.httpRequest(
'https://docs.mapbox.com/llms.txt',
{
headers: {
Accept: 'text/markdown, text/plain;q=0.9, */*;q=0.8'
}
}
);

if (!response.ok) {
throw new Error(
`Failed to fetch Mapbox documentation: ${response.statusText}`
);
}

const content = await response.text();

return {
contents: [
{
uri: uri.href,
mimeType: this.mimeType,
text: content
}
]
};
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : 'Unknown error occurred';
throw new Error(`Failed to fetch Mapbox documentation: ${errorMessage}`);
}
}
}
5 changes: 4 additions & 1 deletion src/resources/resourceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import { MapboxStyleLayersResource } from './mapbox-style-layers-resource/Mapbox
import { MapboxStreetsV8FieldsResource } from './mapbox-streets-v8-fields-resource/MapboxStreetsV8FieldsResource.js';
import { MapboxTokenScopesResource } from './mapbox-token-scopes-resource/MapboxTokenScopesResource.js';
import { MapboxLayerTypeMappingResource } from './mapbox-layer-type-mapping-resource/MapboxLayerTypeMappingResource.js';
import { MapboxDocumentationResource } from './mapbox-documentation-resource/MapboxDocumentationResource.js';
import { httpRequest } from '../utils/httpPipeline.js';

// Central registry of all resources
export const ALL_RESOURCES = [
new MapboxStyleLayersResource(),
new MapboxStreetsV8FieldsResource(),
new MapboxTokenScopesResource(),
new MapboxLayerTypeMappingResource()
new MapboxLayerTypeMappingResource(),
new MapboxDocumentationResource({ httpRequest })
] as const;

export type ResourceInstance = (typeof ALL_RESOURCES)[number];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class GetMapboxDocSourceTool extends BaseTool<
> {
name = 'get_latest_mapbox_docs_tool';
description =
'Get the latest official Mapbox documentation, APIs, SDKs, and developer resources directly from Mapbox. Always up-to-date, comprehensive coverage of all current Mapbox services including mapping, navigation, search, geocoding, and mobile SDKs. Use this for accurate, official Mapbox information instead of web search.';
'Get the latest official Mapbox documentation, APIs, SDKs, and developer resources directly from Mapbox. Always up-to-date, comprehensive coverage of all current Mapbox services including mapping, navigation, search, geocoding, and mobile SDKs. Use this for accurate, official Mapbox information instead of web search. For clients that support resources, use resource://mapbox-documentation for proper text/markdown MIME type support.';
readonly annotations = {
readOnlyHint: true,
destructiveHint: false,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/get-reference-tool/GetReferenceTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class GetReferenceTool extends BaseTool<typeof GetReferenceSchema> {
content: [
{
type: 'text',
text: result.contents[0].text
text: result.contents[0].text as string
}
],
isError: false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Mapbox, Inc.
// Licensed under the MIT License.

import { describe, expect, it } from 'vitest';
import { MapboxDocumentationResource } from '../../../src/resources/mapbox-documentation-resource/MapboxDocumentationResource.js';
import { setupHttpRequest } from '../../utils/httpPipelineUtils.js';

describe('MapboxDocumentationResource', () => {
it('should have correct metadata', () => {
const { httpRequest } = setupHttpRequest();
const resource = new MapboxDocumentationResource({ httpRequest });

expect(resource.name).toBe('Mapbox Documentation');
expect(resource.uri).toBe('resource://mapbox-documentation');
expect(resource.mimeType).toBe('text/markdown');
expect(resource.description).toContain(
'Latest official Mapbox documentation'
);
});

it('should successfully fetch documentation content with proper MIME type', async () => {
const mockContent = `# Mapbox Documentation

This is the Mapbox developer documentation for LLMs.

## Web SDKs
- Mapbox GL JS for interactive maps
- Mobile SDKs for iOS and Android

## APIs
- Geocoding API for address search
- Directions API for routing`;

const { httpRequest, mockHttpRequest } = setupHttpRequest({
ok: true,
status: 200,
text: () => Promise.resolve(mockContent)
});

const resource = new MapboxDocumentationResource({ httpRequest });
const uri = new URL('resource://mapbox-documentation');
const result = await resource.readCallback(uri, {} as any);

expect(mockHttpRequest).toHaveBeenCalledWith(
'https://docs.mapbox.com/llms.txt',
{
headers: {
Accept: 'text/markdown, text/plain;q=0.9, */*;q=0.8',
'User-Agent': 'TestServer/1.0.0 (default, no-tag, abcdef)'
}
}
);

expect(result.contents).toHaveLength(1);
expect(result.contents[0]).toMatchObject({
uri: 'resource://mapbox-documentation',
mimeType: 'text/markdown',
text: mockContent
});
});

it('should handle HTTP errors', async () => {
const { httpRequest } = setupHttpRequest({
ok: false,
status: 404,
statusText: 'Not Found'
});

const resource = new MapboxDocumentationResource({ httpRequest });
const uri = new URL('resource://mapbox-documentation');

await expect(resource.readCallback(uri, {} as any)).rejects.toThrow(
'Failed to fetch Mapbox documentation: Not Found'
);
});

it('should handle network errors', async () => {
const { httpRequest } = setupHttpRequest({
text: () => Promise.reject(new Error('Network error'))
});

const resource = new MapboxDocumentationResource({ httpRequest });
const uri = new URL('resource://mapbox-documentation');

await expect(resource.readCallback(uri, {} as any)).rejects.toThrow(
'Failed to fetch Mapbox documentation: Network error'
);
});

it('should handle unknown errors', async () => {
const { httpRequest } = setupHttpRequest({
text: () => Promise.reject('String error')
});

const resource = new MapboxDocumentationResource({ httpRequest });
const uri = new URL('resource://mapbox-documentation');

await expect(resource.readCallback(uri, {} as any)).rejects.toThrow(
'Failed to fetch Mapbox documentation: Unknown error occurred'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ exports[`Tool Naming Convention > should maintain consistent tool list (snapshot
},
{
"className": "GetMapboxDocSourceTool",
"description": "Get the latest official Mapbox documentation, APIs, SDKs, and developer resources directly from Mapbox. Always up-to-date, comprehensive coverage of all current Mapbox services including mapping, navigation, search, geocoding, and mobile SDKs. Use this for accurate, official Mapbox information instead of web search.",
"description": "Get the latest official Mapbox documentation, APIs, SDKs, and developer resources directly from Mapbox. Always up-to-date, comprehensive coverage of all current Mapbox services including mapping, navigation, search, geocoding, and mobile SDKs. Use this for accurate, official Mapbox information instead of web search. For clients that support resources, use resource://mapbox-documentation for proper text/markdown MIME type support.",
"toolName": "get_latest_mapbox_docs_tool",
},
{
Expand Down
Loading