Compare commits
2 Commits
main
...
osc/108-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a95436d7b6 | ||
|
|
1a928b789d |
@ -3,6 +3,7 @@
|
||||
## [Unreleased]
|
||||
|
||||
### CLI
|
||||
- Render `resource` content blocks in call output helpers instead of dropping them, including markdown resources and JSON text payloads. (PR #124, thanks @mvanhorn)
|
||||
- Preserve default imports when `mcporter config add` writes a config file, instead of forcing `"imports": []`.
|
||||
- OAuth: avoid crashing on headless Linux when `xdg-open` is unavailable; clear stale dynamic-port client registrations; close callback server if stale-client persistence reads fail. (PR #72, thanks @mgonto)
|
||||
- Added optional `oauthScope`/`oauth_scope` config override as an escape hatch for providers that require explicit scopes.
|
||||
|
||||
@ -116,6 +116,26 @@ function collectCallContent(raw: unknown): CollectedCallContent {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (typedEntry.type === 'resource') {
|
||||
const resource = typedEntry.resource as Record<string, unknown> | undefined;
|
||||
if (resource && typeof resource === 'object') {
|
||||
const uri = typeof resource.uri === 'string' ? resource.uri : '';
|
||||
const mimeType = typeof resource.mimeType === 'string' ? resource.mimeType : '';
|
||||
if (typeof resource.text === 'string') {
|
||||
textEntries.push(resource.text);
|
||||
if (mimeType.toLowerCase().includes('markdown')) {
|
||||
markdownEntries.push(resource.text);
|
||||
}
|
||||
const parsed = tryParseJson(resource.text);
|
||||
if (parsed !== null) {
|
||||
jsonCandidates.push(parsed);
|
||||
}
|
||||
} else if (typeof resource.blob === 'string') {
|
||||
textEntries.push(`[Binary resource: ${uri}]`);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (typedEntry.type !== 'text' && typedEntry.type !== 'markdown') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -217,6 +217,94 @@ describe('createCallResult json extraction', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createCallResult resource extraction', () => {
|
||||
it('extracts text from resource content blocks', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'file:///repo/README.md',
|
||||
mimeType: 'text/markdown',
|
||||
text: '# My Project\n\nA description.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.text()).toBe('# My Project\n\nA description.');
|
||||
});
|
||||
|
||||
it('treats markdown resources as markdown output too', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'file:///repo/README.md',
|
||||
mimeType: 'text/markdown',
|
||||
text: '# My Project\n\nA description.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.markdown()).toBe('# My Project\n\nA description.');
|
||||
});
|
||||
|
||||
it('creates placeholder for binary resource content blocks', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'file:///repo/logo.png',
|
||||
mimeType: 'image/png',
|
||||
blob: 'aGVsbG8=',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.text()).toBe('[Binary resource: file:///repo/logo.png]');
|
||||
});
|
||||
|
||||
it('extracts text from mixed content blocks including resources', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{ type: 'text', text: 'Here is the file:' },
|
||||
{
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'file:///repo/src/index.ts',
|
||||
mimeType: 'text/typescript',
|
||||
text: 'console.log("hello");',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.text()).toBe('Here is the file:\nconsole.log("hello");');
|
||||
});
|
||||
|
||||
it('parses JSON from resource text content', () => {
|
||||
const response = {
|
||||
content: [
|
||||
{
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'file:///repo/config.json',
|
||||
mimeType: 'application/json',
|
||||
text: '{"key":"value"}',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = createCallResult(response);
|
||||
expect(result.json()).toEqual({ key: 'value' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('createCallResult structured accessors', () => {
|
||||
it('content() returns nested raw content array', () => {
|
||||
const nested = [{ type: 'text', text: 'Hello' }];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user